//
// Created by par on 2022/11/14.
//
#include <fmt/core.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
#include <unistd.h>
#include <filesystem>
#include <string>
#include <thread>
#include <vector>

#include "arg.hpp"
#include "sock.hpp"

using namespace std;
namespace fs = filesystem;

int init_serv(ServerArgs &args) {
    auto sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        fmt::print("create socket fail\n");
        exit(EXIT_FAILURE);
    }

    sockaddr_in serv_addr = {};
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(args.port);
    // xx.xx.xx.xx -> struct in_addr
    if (!inet_aton(args.listen.c_str(), &serv_addr.sin_addr)) {
        fmt::print("failed to start fserver: {} is not a valid address\n", args.listen);
        exit(EXIT_FAILURE);
    }

    if (bind(sockfd, reinterpret_cast<sockaddr *>(&serv_addr), sizeof(serv_addr))) {
        fmt::print("failed to start fserver: {}:{} already in use\n", inet_ntoa(serv_addr.sin_addr),
                   ntohs(serv_addr.sin_port));
        exit(EXIT_FAILURE);
    }

    // 设置可接纳的请求数?
    if (listen(sockfd, 10)) {
        fmt::print("listen fail\n");
        exit(EXIT_FAILURE);
    }
    cout << fmt::format("server listening at {}:{}", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)) << endl;

    return sockfd;
}

string get_filelist(string &dir) {
    string info = "file lists:\n";
    for (auto &p: fs::recursive_directory_iterator(dir)) {
        if (p.is_regular_file()) {
            // cout << "\t" << p << endl;
            info += "\t";
            info += p.path().string();
            info += "\n";
        }
    }

    return info;
}

int main(int argc, char *argv[]) {
    auto args = parse_serv_args(argc, argv);

//    cout << fmt::format("listen: {}, hidden: {}, port: {}, dir:{}",
//                        args.listen, args.hidden, args.port, args.dir) << endl;

    auto sockfd = init_serv(args);

    cout << get_filelist(args.dir) << endl;

    sockaddr_in cli_addr;
    socklen_t len;
    int clifd;
    while (true) {
        // 阻塞等待请求
        if ((clifd = accept(sockfd, reinterpret_cast<sockaddr *>(&cli_addr), &len)) < 0) {
            fmt::print("accept fail\n");
//             continue;
            exit(EXIT_FAILURE);
        }
        cout << fmt::format("accept client {}:{}", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)) << endl;

        // clifd值传递!
        thread t([clifd, &args]() {
            string cmd = recvStr(clifd);
            if (cmd == "list") {
                sendStr(clifd, get_filelist(args.dir));
            } else if (cmd == "dl") {
                auto filename = recvStr(clifd);

                sendFile(clifd, filename);
            }
            close(clifd);
        });
        // 主线程永不停
        t.detach();
    }

    // 主线程永不停
//    close(sockfd);
//    return 0;
}